#ifndef PCB_H
#define PCB_H

#include "types.h"
#include "registers.h"
#include "message_queue.h"
#include "error_codes.h"
#include "system_id.h"
#include "dynamic_memory.h"
#include "states.h"

/* type declarations */

/* PCB definition */
typedef struct _pcb{
  registers_t registers;
  uint32_t priority;
  int32_t pid;
  int32_t parent;
  uint32_t state;
  uint32_t program_id;
  int32_t waiting_for; //store the pid the process is waiting for during a call to wait
  int32_t status; //store the return value when the process terminates
  uint32_t delay;
  uint32_t stack; //memorize the initial address of the stack (needed to free it)
  message_queue m_queue; //message queue 
  list supervisors;
  list supervised;
}PCB;

/* function declarations */

/* initializes a pcb */
void initialize_pcb(PCB* pcb);

/* compares two pcb. Returns 1 if they are the same, 0 otherwise */
int32_t compare_pcb(void* arg1, void* arg2);

/* frees pcb */
int32_t free_pcb(void* arg);

/* setters */
void pcb_set_priority(PCB* target, int32_t priority);

void pcb_set_pid(PCB* target, int32_t pid);

void pcb_set_epc(PCB* target, uint32_t pc);

void pcb_set_state(PCB* target, uint32_t state);

void pcb_set_sp(PCB* target, uint32_t address);

void pcb_set_stack(PCB* target, uint32_t address);

void pcb_set_delay(PCB* target, uint32_t delay);

void pcb_set_program_id(PCB* target, int32_t program_id);

void pcb_set_parent(PCB* target, int32_t parent); 

void pcb_set_waiting_for(PCB* target, int32_t pid);

void pcb_set_status(PCB* target, int32_t status);

void pcb_set_ra(PCB* target, uint32_t address);

/* getters */
int32_t pcb_get_pid(PCB* target);

int32_t pcb_get_priority(PCB* target);

uint32_t pcb_get_state(PCB* target);

uint32_t pcb_get_delay(PCB* target);

uint32_t pcb_get_epc(PCB* target);

/* returns a pointer to the registers field of a PCB */
registers_t* pcb_get_registers(PCB* target);

int32_t pcb_get_program_id(PCB* target);

/* returns a pointer to the message queue of the PCB */
message_queue* pcb_get_message_queue(PCB* target);

int32_t pcb_get_parent(PCB* target);

int32_t pcb_get_waiting_for(PCB* target);

int32_t pcb_get_status(PCB* target);

list* pcb_get_supervisors(PCB* target);

list* pcb_get_supervised(PCB* target);

#endif


